/**
 * tjftp -- A simple FTP server, using the ANSI C
 * Copyright (C) 2011  degui.chen <degui.chen@qq.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <errno.h>
#include "lib/memory.h"
#include "lib/file.h"
#include "lib/string.h"
#include "lib/settings.h"
#include "lib/log.h"
#include "lib/sockets.h"
#include "plugin.h"
#include "lib/unity.h"
#include "command.h"
#include "dispatcher.h"
#include "observer.h"
#include "sesstion.h"

static volatile sig_atomic_t server_shutdown = 0; 
void ts_signal_handler(int sig) {
	char temp[255] = { '\0' };
	sprintf(temp, "进程[%i] 收到结束通知, 通过信号 %d", getpid(), sig);
	DEBUG_LOG(temp, 0)

	server_shutdown = 1;
}
void ts_signal_init() {
	signal(SIGALRM, ts_signal_handler);
	signal(SIGTERM, ts_signal_handler);
	signal(SIGHUP, ts_signal_handler);
	signal(SIGCHLD, ts_signal_handler);
	signal(SIGINT, ts_signal_handler);
}
int main(int argc, char* argv[]) {
	PSettings settings = tj_settings_create(argc, argv);
	//tj_settings_dump(settings);
	DEBUG_LOG("守护进程", 0);
	DEBUG_LOG("信号处理", 0);
	ts_signal_init();
	DEBUG_LOG("日志初始化", 0);
	tj_log_open(settings);
	DEBUG_LOG("Socket初始化", 0);
	//set_sockets_debut_mode();
	int socket_fd = tj_create_tcp_socket();
	tj_tcp_open_listen(socket_fd, settings->bind_port, settings->listen_queue_max_length);
	DEBUG_LOG("插件初始化", 0);
	tj_plugin_init(settings, socket_fd);
	DEBUG_LOG("主循环", 0);
	DEBUG_LOG("通知进入主循环之前", 0);
	tj_plugin_loop_pre();

	char temp[255] = { '\0' };
	sprintf(temp, "创建多个进程, 个数 [%i].", settings->max_process);
	DEBUG_LOG(temp, 0)

	if (1 < settings->max_process) {//是否使用多进程
		int max_worker = settings->max_process;
		int child = 0;
		while (!child && !server_shutdown) { //父进程一直在这里，直到退出，退出在下面处理，子进程继续执行
			if (max_worker > 0) {
				switch (fork()) {
					case -1: //异常退出
						return -1;
					case 0://子进程退出 while, 继续往下执行
						child = 1;
						char temp[255] = { '\0' };
						sprintf(temp, "创建进程 [%i].", getpid());
						DEBUG_LOG(temp, 0)
						break;
					default://父进程，继续留在这里创建子进程
						max_worker--;
						break;
				}
			} else {
				int status;
				if (-1 != wait(&status)) {
					max_worker++;
				} else {
					//if (EINTR == errno) {
					kill(0, SIGINT);
					break;
					//}
				}
			}
		}
		if (!child) { //父进程的退出处理
			if (server_shutdown) {
				char temp[255] = { '\0' };
				sprintf(temp, "结束进程 [%i].", getpid());
				DEBUG_LOG(temp, 0)
				kill(0, SIGINT);//通知所有子进程，设置 signal_shutdown  = 1.
			}
			return 0;
		}
	}
	while (!server_shutdown) {
		int i;
		int accept_fd = tj_tcp_accept(socket_fd);
		if (-1 == accept_fd) {
			continue;
		}
		tj_sesstion_init(accept_fd, settings);
		DEBUG_LOG("通知开始请求用户信息", 0);
		int result = tj_plugin_connects(accept_fd); //这里用于登录验证, 因为用户 TCP 会话标识就是 accept_fd
		if (!result) {//验证通过
			do {
				result = tj_dispatch_client(accept_fd);
			} while (-1 != result);
		}
		if (-1 == result) {
			DEBUG_LOG("通知结束请求用户信息", 0);
			tj_plugin_disconnect(accept_fd);
			tj_sesstion_destory(accept_fd);
			close(accept_fd);
		}
	}
	/*
	DEBUG_LOG("使用 IO 复用技术", 0);
	struct epoll_event polls, events[20];
	int epfd = epoll_create(256);

	polls.data.fd = socket_fd;
	polls.events = EPOLLIN;
	epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &polls);
	int nfds;
	while (!server_shutdown) {
		nfds = epoll_wait(epfd, events, 20, 500);
		int i;
		for (i = 0; i < nfds; i++) {
			if (events[i].data.fd == socket_fd) { //如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口，建立新的连接。
				int accept_fd = tj_tcp_accept(socket_fd);
				if (-1 == accept_fd) {
					continue;
				}
				polls.data.fd = accept_fd;
				polls.events = EPOLLIN;
				epoll_ctl(epfd, EPOLL_CTL_ADD, accept_fd, &polls);
				tj_sesstion_init(polls.data.fd, settings);
			} else if (events[i].events & EPOLLIN) { //如果是已经连接的用户，并且收到数据，那么进行读入。
				if (events[i].data.fd < 0) { //过滤处理完成的句柄
					continue;
				}
				DEBUG_LOG("通知开始请求用户信息", 0);
				int result = tj_plugin_connects(events[i].data.fd); //这里用于登录验证, 因为用户 TCP 会话标识就是 accept_fd
				if (!result) { //验证通过
					result = tj_dispatch_client(events[i].data.fd);
				}
				if (-1 == result) {
					DEBUG_LOG("通知结束请求用户信息", 0);
					tj_plugin_disconnect(events[i].data.fd);
					tj_sesstion_destory(events[i].data.fd);
					close(events[i].data.fd);
					events[i].data.fd = -1;
				}
			} else {
				//处理其他请求
			}
		}
	}
	//*/
	DEBUG_LOG("通知退出主循环信息", 0);
	tj_plugin_loop_post();
	tj_log_write("test");
	DEBUG_LOG("清除插件", 0);
	tj_plugin_destory();
	DEBUG_LOG("清除Socket", 0);
	tj_sockets_close(socket_fd);
	DEBUG_LOG("关闭日志", 0);
	sleep(1);
	tj_log_close();
	DEBUG_LOG("清除配置", 0);
	tj_settings_destory(settings);
	observer_destroy();
	return 0;
}
